'''
Created on Mar 25, 2014

@author: Eric
'''

import os.path
import re

#######

class ModuleAmbiguityError(Exception):
    
    def __init__(self, path, root1, root2):
        super(ModuleAmbiguityError, self).__init__(path, root1, root2)
        self.path = path
        self.root1 = root1
        self.root2 = root2
    
    def __str__(self):
        msg = "Duplicate module path '%s' from roots '%s' and '%s'"
        return msg % (self.path, self.root1, self.root2)

#######

class InvalidPathError(Exception):
    
    def __init__(self, base, path):
        super(InvalidPathError, self).__init__(base, path)
        self.base = base
        self.path = path
    
    def __str__(self):
        msg = "Invalid module path '%s' (base is '%s')"
        return msg % (self.path, self.base)

#######

ROOTS_ENVVAR  = 'TUNGSTEN_ROOTS'
SRC_EXTENSION = '.w'

#######

MODULE_NAME_RE = re.compile('^[a-z][a-z0-9_]*$')

class Domain(object):
    
    def __init__(self, roots = None):
        self.roots = roots or os.environ[ROOTS_ENVVAR]
        if isinstance(self.roots, str):
            self.roots = self.roots.split(';')
        self.catalog = self._build_catalog()
    
    def _build_catalog(self):
        result = {}
        for root in self.roots:
            for (dirpath, _, filenames) in os.walk(root):
                base_mod_path = os.path.relpath(dirpath, root).split(os.path.sep)
                if base_mod_path[0] == '.':
                    del base_mod_path[0]
                if all([MODULE_NAME_RE.match(x) for x in base_mod_path]):
                    for filename in filenames:
                        (fn_base, fn_ext) = os.path.splitext(filename)
                        if (fn_ext.lower() == SRC_EXTENSION) and MODULE_NAME_RE.match(fn_base):
                            mod_path = '.'.join(base_mod_path + [fn_base])
                            if mod_path in result:
                                raise ModuleAmbiguityError(mod_path, result[mod_path][0], root)
                            result[mod_path] = (root, os.path.abspath(os.path.join(dirpath, filename)))
        return result

    def __getitem__(self, key):
        return self.catalog[key][1]

    def read(self, path):
        if path in self.catalog:
            handle = open(self.catalog[path][1])
            text = handle.read()
            handle.close()
            return text

#######

def join(base, path):
    base2 = base.split('.')
    path2 = path.split('.')
    current = []
    first = True
    for x in path2:
        if first:
            if not x:
                current = base2
            else:
                current.append(x)
            first = False
        else:
            if not x:
                if not current:
                    raise InvalidPathError(base, path)
                else:
                    current.pop()
            else:
                current.append(x)
    return '.'.join(current)

